package com.atguigu.stream.exer01;

import com.atguigu.lambda.exer01.Employee;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/**
 * 一、Stream的三个操作步骤“
 * 1、创建Stream
 *
 * 2、中间操作
 *
 * 3、终止操作(终端操作)
 *
 *
 */

public class TestStreamAPI2 {

    List<Employee> employees = Arrays.asList(
            new Employee(101,"张三", 18, 9999.99),
            new Employee(102,"李四", 38, 5555.99),
            new Employee(103,"王五", 50, 6666.66),
            new Employee(104,"赵六", 16, 3333.33),
            new Employee(105,"田七", 8, 7777.77),
            new Employee(106,"田七", 8, 7777.77),
            new Employee(107,"田七", 8, 7777.77)
    );

    // 中间操作

    /**
     * 排序：
     * sorted()：自然排序(Comparable) 就是按照从小到大排序
     * sorted(Comparator c)：定制排序(Comparator) 按照自己制定的规则排序
     */

    @Test
    public void test7() {
        List<String> list = Arrays.asList("ccc", "aaa", "bbb", "ddd", "eee");

        list.stream()
            .sorted()
            .forEach(System.out::println);

        System.out.println("--------------------------");

        // 定制排序：先按年龄排序，年龄一样按姓名排序
        employees.stream()
                 .sorted((e1, e2) -> {
                    if (e1.getAge().equals(e2.getAge())) {
                        return e1.getName().compareTo(e2.getName());
                    } else {
                        return e1.getAge().compareTo(e2.getAge());
                    }
                 }).forEach(System.out::println);

    }


    /**
     * map：接收 Lambda ，将元素转换为其他形式或提取信息；接受一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素
     * flatMap：接收一个函数作为参数，将流中每一个值都换成另一个流，然后把所有流重新连接成一个流
     */
    @Test
    public void test6() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
        List list2 = new ArrayList();
        list2.add(11);
        list2.add(22);
        // list2.add(list);
        list2.addAll(list);
        System.out.println(list2);
    }

    @Test
    public void test5() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");

        list.stream()
            .map((str) -> str.toUpperCase())
            .forEach(System.out::println);

        System.out.println("------------------------------------");

        employees.stream()
                 .map(Employee::getName) // 提取名字
                 .distinct()
                 .forEach(System.out::println);

        System.out.println("------------------------------------");

/*        Stream<Stream<Character>> stream = list.stream()
                .map(TestStreamAPI2::filterCharacter); // {{a,a,a},{b,b,b} .....} 相当于把一个一个的流加入另一个流中

        stream.forEach((sm) -> {
            sm.forEach(System.out::println);
        });*/

        System.out.println("-------------------------------------");

        Stream<Character> sm = list.stream()
                .flatMap(TestStreamAPI2::filterCharacter); // {a,a,a,b,b,b ......} 相当于把一个一个流中的元素加入另一个流中

        sm.forEach(System.out::println);

    }

    public static Stream<Character> filterCharacter(String str) {
        List<Character> list = new ArrayList<>();

        for (Character ch : str.toCharArray()) { // 把字符串的字符一个一个提取出来然后放进集合里
            list.add(ch);
        }

        return list.stream();
    }

    /**
     * 筛选与切片：
     * filter：接收 Lambda ，从流中排除某些元素
     * limit：截断流，使其元素不超过给定数量
     * skip(n)：跳过元素，返回一个舍弃了前n个元素的流；若流中元素不足n个，则返回一个空流；与 limit(n) 互补
     * distinct：筛选，通过流所生成的 hashCode() 与 equals() 取除重复元素
     *
     */

    @Test
    public void test4() {
        employees.stream()
                 .filter((e) -> e.getSalary() > 5000)
                 .skip(2) // 跳过前2个结果，取后面满足条件的结果
                 .distinct() // 要想去重还需Employee实现hashCode() 与 equals()
                 .forEach(System.out::println);
    }

    @Test
    public void test3() {
        employees.stream()
                 .filter((e) -> { // 查找到满足条件的结果后，后续迭代的操作就不再进行了，这个就叫做短路，类似短路与&&
                     System.out.println("短路！");
                     return e.getSalary() > 5000;
                 })
                 .limit(2)
                 .forEach(System.out::println);
    }

    // 内部迭代：迭代操作由Stream API 完成
    @Test
    public void test1() {

        // 中间操作：不会执行任何操作
        Stream<Employee> stream = employees.stream()
                .filter((e) -> {
                    System.out.println("Stream API 的中间操作");
                    return e.getAge() > 35;
                });

        // 终止操作：一次性执行全部内容，即”惰性求值“
        stream.forEach(System.out::println);
    }

    // 外部迭代：
    @Test
    public void test2() {
        Iterator<Employee> iterator = employees.iterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }

}
